package formatter

import (
	"bytes"
	"fmt"
	"go-quick/interface/ilogger"
	"time"
)

type ColorType int

const (
	colorReset   ColorType = 0
	colorRed               = 31
	colorGreen             = 32
	colorYellow            = 33
	colorBlue              = 34
	colorMagenta           = 35
	colorCyan              = 36
	colorWhite             = 37
)

var (
	red     = []byte("\033[31m")
	green   = []byte("\033[32m")
	yellow  = []byte("\033[33m")
	blue    = []byte("\033[34m")
	magenta = []byte("\033[35m")
	cyan    = []byte("\033[36m")
	white   = []byte("\033[37m")
	reset   = []byte("\033[0m")
)

func colorStr(color ColorType, ctx string) string {
	switch color {
	case colorRed:
		return fmt.Sprintf("\033[%dm%s\033[0m", colorRed, ctx)
	case colorGreen:
		return fmt.Sprintf("\033[%dm%s\033[0m", colorGreen, ctx)
	case colorYellow:
		return fmt.Sprintf("\033[%dm%s\033[0m", colorYellow, ctx)
	case colorBlue:
		return fmt.Sprintf("\033[%dm%s\033[0m", colorBlue, ctx)
	case colorMagenta:
		return fmt.Sprintf("\033[%dm%s\033[0m", colorMagenta, ctx)
	case colorCyan:
		return fmt.Sprintf("\033[%dm%s\033[0m", colorCyan, ctx)
	case colorWhite:
		return fmt.Sprintf("\033[%dm%s\033[0m", colorWhite, ctx)
	default:
		return fmt.Sprintf("\033[%dm%s\033[0m", colorBlue, ctx)
	}
}

type TextFormatter struct {
	ForceColors  bool //
	DisableColor bool // 是否禁用颜色
}

func DefaultTextFormatter() *TextFormatter {
	return &TextFormatter{
		ForceColors:  false,
		DisableColor: false,
	}
}

func (t *TextFormatter) Format(entry ilogger.IEntry) ([]byte, error) {
	var (
		timeData time.Time
		mapData  map[string]any
		buf      *bytes.Buffer
		getLevel = func(level ilogger.LogLevel) string {
			switch level {
			case ilogger.InfoLevel:
				return "Info"
			case ilogger.DebugLevel:
				return "Debug"
			case ilogger.WarnLevel:
				return "Warn"
			case ilogger.ErrorLevel:
				return "Error"
			case ilogger.FailLevel:
				return "Fail"
			default:
				return "Other"
			}
		}
		getColorLevel = func(level ilogger.LogLevel) string {
			switch level {
			case ilogger.InfoLevel:
				return colorStr(colorBlue, "Info")
			case ilogger.DebugLevel:
				return colorStr(colorGreen, "Debug")
			case ilogger.WarnLevel:
				return colorStr(colorYellow, "Warn")
			case ilogger.ErrorLevel:
				return colorStr(colorRed, "Error")
			case ilogger.FailLevel:
				return colorStr(colorRed, "Fail")
			default:
				return colorStr(colorBlue, "Other")
			}
		}
		dataMap   ilogger.Fields
		dataValue any
		funcName  any
		fileName  any
		ok        bool
	)
	mapData, buf = entry.ToMap(), &bytes.Buffer{}
	timeData = mapData[ilogger.FieldKeyTime].(time.Time)
	if t.DisableColor {
		buf.Write([]byte(fmt.Sprintf("[%s] [%s] [%s] ",
			mapData[ilogger.FieldKeyPrefix],
			timeData.Format(ilogger.DefaultTimeFormat),
			getLevel(mapData[ilogger.FieldKeyLevel].(ilogger.LogLevel)))),
		)
	} else {
		buf.Write([]byte(fmt.Sprintf("[%s] [%s] [%s] ",
			colorStr(colorBlue, mapData[ilogger.FieldKeyPrefix].(string)),
			colorStr(colorWhite, timeData.Format(ilogger.DefaultTimeFormat)),
			getColorLevel(mapData[ilogger.FieldKeyLevel].(ilogger.LogLevel)))),
		)
	}
	if fileName, ok = mapData[ilogger.FieldKeyFile]; ok {
		buf.Write([]byte(fmt.Sprintf("[%s] ", fileName)))
	}
	if funcName, ok = mapData[ilogger.FieldKeyFunc]; ok {
		buf.Write([]byte(fmt.Sprintf("[%s] ", funcName)))
	}
	buf.Write([]byte(fmt.Sprintf("%s ", mapData[ilogger.FieldKeyMsg])))
	if dataValue, ok = mapData[ilogger.FieldKeyData]; ok {
		dataMap = dataValue.(ilogger.Fields)
		buf.WriteByte('[')
		for k, v := range dataMap {
			t.appendKeyValue(buf, k, v)
		}
		buf.WriteString(" ]")
	}
	buf.WriteByte('\n')
	return buf.Bytes(), nil
}

// appendKeyValue 添加 key 和 value
func (t *TextFormatter) appendKeyValue(buf *bytes.Buffer, key string, value any) {
	if buf.Len() > 0 {
		buf.WriteByte(' ')
	}
	buf.WriteString(key)
	buf.WriteByte('=')
	buf.WriteString(fmt.Sprintf("%q", value))
}
